package com.haibara.aiojcodesandbox.utils;

import cn.hutool.core.util.StrUtil;
import com.haibara.aiojcodesandbox.model.ExecuteMessage;
import lombok.extern.slf4j.Slf4j;
import org.apache.tomcat.util.buf.StringUtils;
import org.springframework.util.StopWatch;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.List;

/**
 * 进程处理工具类
 *
 * @author 程崎
 * @since 2023/08/25
 */
@Slf4j
public class ProcessUtil {

    /**
     * 运行进行
     *
     * @param runProcess    运行进程
     * @param operationName 操作名称
     * @return {@link ExecuteMessage}
     */
    public static ExecuteMessage handleProcessMessage(Process runProcess, String operationName) {
        int exitCode;
        StringBuilder output = new StringBuilder();
        StringBuilder errorOutput = new StringBuilder();
        try {
            exitCode = runProcess.waitFor();
            if (exitCode == 0) {
                log.info(operationName + "成功");
            } else {
                log.error(operationName + "失败，错误码为: {}", exitCode);
                BufferedReader errorBufferedReader = new BufferedReader(new InputStreamReader(runProcess.getErrorStream()));
                String errorRunOutputLine;
                while ((errorRunOutputLine = errorBufferedReader.readLine()) != null) {
                    errorOutput.append(errorRunOutputLine);
                }
                log.error("错误输出为：{}", errorOutput);
            }
            BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(runProcess.getInputStream()));
            String runOutputLine;
            while ((runOutputLine = bufferedReader.readLine()) != null) {
                output.append(runOutputLine);
            }
            if (StrUtil.isNotBlank(output)) {
                log.info("正常输出：{}", output);
            }
        } catch (IOException | InterruptedException e) {
            throw new RuntimeException(e);
        }
        return ExecuteMessage.builder()
                .exitCode(exitCode)
                .message(output.toString())
                .errorMessage(errorOutput.toString())
                .build();
    }


    public static ExecuteMessage handleProcessInteraction(Process runProcess, String input, String operationName) {
        OutputStream outputStream = runProcess.getOutputStream();
        try {
            outputStream.write((input + "\n").getBytes());
            outputStream.flush();
            outputStream.close();
            return handleProcessMessage(runProcess, operationName);
        } catch (IOException e) {
            throw new RuntimeException(e);
        } finally {
            try {
                outputStream.close();
            } catch (IOException e) {
                log.error("关闭输入流失败");
            }
        }
    }

    public static ExecuteMessage runProcessAndGetMessage(Process runProcess, String opName) {
        ExecuteMessage executeMessage = new ExecuteMessage();

        try {
            StopWatch stopWatch = new StopWatch();
            stopWatch.start();
            // 等待程序执行，获取错误码
            int exitValue = runProcess.waitFor();
            executeMessage.setExitCode(exitValue);
            // 正常退出
            if (exitValue == ExecuteMessage.SUCCESS) {
                System.out.println(opName + "成功");
                // 分批获取进程的正常输出
                BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(runProcess.getInputStream()));
                List<String> outputStrList = new ArrayList<>();
                // 逐行读取
                String compileOutputLine;
                while ((compileOutputLine = bufferedReader.readLine()) != null) {
                    outputStrList.add(compileOutputLine);
                }
                // 获取内存
                if(outputStrList.isEmpty()){
                    return null;
                }
                List<String> outputDataList = new ArrayList<>();
                for (int i = 0; i < outputStrList.size()-1; i++) {
                    outputDataList.add(outputStrList.get(i));
                }
                double memory = Double.parseDouble(outputStrList.get(outputStrList.size()-1));
                executeMessage.setMemory(memory);
                executeMessage.setMessage(StringUtils.join(outputDataList, '\n'));
            } else {
                // 异常退出
                System.out.println(opName + "失败，错误码： " + exitValue);
                // 分批获取进程的正常输出
//                BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(runProcess.getInputStream()));
//                List<String> outputStrList = new ArrayList<>();
//                // 逐行读取
//                String compileOutputLine;
//                while ((compileOutputLine = bufferedReader.readLine()) != null) {
//                    outputStrList.add(compileOutputLine);
//                }
                // 获取内存
//                if(outputStrList.isEmpty()){
//                    return null;
//                }
                // 获取内存
//                List<String> outputDataList = new ArrayList<>();
//                for (int i = 0; i < outputStrList.size()-1; i++) {
//                    outputDataList.add(outputStrList.get(i));
//                }
//                double memory = Double.parseDouble(outputStrList.get(outputStrList.size()-1));
//                executeMessage.setMemory(memory);
//                executeMessage.setMessage(StringUtils.join(outputDataList, '\n'));

                // 分批获取进程的错误输出
                BufferedReader errorBufferedReader = new BufferedReader(new InputStreamReader(runProcess.getErrorStream()));
                // 逐行读取
                List<String> errorOutputStrList = new ArrayList<>();
                // 逐行读取
                String errorCompileOutputLine;
                while ((errorCompileOutputLine = errorBufferedReader.readLine()) != null) {
                    errorOutputStrList.add(errorCompileOutputLine);
                }
//                executeMessage.setMemory(memory);
                executeMessage.setErrorMessage(StringUtils.join(errorOutputStrList, '\n'));
            }
            stopWatch.stop();
            executeMessage.setTime(stopWatch.getLastTaskTimeMillis());
        } catch (Exception e) {
            e.printStackTrace();
        }
        return executeMessage;
    }
}
